package juc.thread.secuity;

import java.io.FileInputStream;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

/*
* 同步模式之保护性暂停（guarded suspension）特点:产生结果者与等待结果者一一对应
* */
public class Test9 {
    //测试一个线程下载 另一个线程等待下载完成
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();
        new Thread(()->{
            //下载
            String download = download();
            guardedObject.complete(null);
        },"下载").start();
        new Thread(()->{
            System.out.println("等待下载...");
            Object o = guardedObject.get(10000);
            System.out.println("下载完成..."+o);
        },"等待下载").start();
    }
    public static String download(){
        String line="";
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try (FileInputStream inputStream = new FileInputStream("test.txt")){

             int read=0;
             while ((read=inputStream.read())>0){
                   line+=read;
             }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return line;
    }
}
/*
* 保护性暂停（guarded suspension） 解耦(rpc框架底层)
* */
class Test10{
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i <5 ; i++) {
            new Thread(new People(),"居民"+i).start();
        }
        Thread.sleep(1000);//
        Set<Integer> idSets = MailBoxes.getIdSets();
        int i=0;
        for (Integer id : idSets) {
            new Thread(new Postman(id),"邮递员"+i++).start();
        }
//        Thread.sleep(7000);
//        System.out.println(MailBoxes.getIdSets().size());
    }
}
class People implements Runnable{

    @Override
    public void run() {
        GuardedMail guardedMail = MailBoxes.GenerateMailBox();
        System.out.println(Thread.currentThread().getName()+"开始等待邮件...");
        Object o = guardedMail.get(7000);
        System.out.println(Thread.currentThread().getName()+"等待结束..."+o);
    }
}
class Postman implements Runnable{
    private Integer recordId;

    public Postman(Integer recordId) {
        this.recordId = recordId;
    }

    @Override
    public void run() {
        GuardedMail guardedMailById = MailBoxes.getGuardedMailById(recordId);
        System.out.println(Thread.currentThread().getName()+"正在派送"+recordId+"...");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        guardedMailById.complete("I LOVE YOU TOM"+recordId);
        System.out.println("派送到了...");
    }
}
final class MailBoxes{
     private final static Map<Integer,GuardedMail>boxes=new Hashtable<>();
     private static Integer ID=1;
     public static GuardedMail GenerateMailBox(){//hashtable本身就是线程安全的
         Integer id = generateId();
         GuardedMail guardedMail = new GuardedMail();
         boxes.put(id,guardedMail);
         return guardedMail;
     }
     private static synchronized Integer generateId(){//同步 防止线程安全问题
            return ID++;
     }
     public static Set<Integer>getIdSets(){//hashtable本身就是线程安全的
         return boxes.keySet();
     }
     public static GuardedMail getGuardedMailById(Integer id){
            return boxes.remove(id);
     }
}
class GuardedMail{
//    private Integer id;
    private Object result;
  /*  public GuardedMail(Integer id) {
        this.id = id;
    }*/
    public void complete(Object o){
        synchronized (this){
            result=o;
            this.notifyAll();//唤醒所有waitSet中的线程
        }
    }
    public Object get(long timeout) {
        synchronized (this) {
            long beginTime = System.currentTimeMillis();
            long passTime = 0;
            while (result == null) {
                long surplusWait = timeout - passTime;//剩余等待时间
                if (surplusWait <= 0) {
                    System.out.println("等待超时...");
                    break;
                } else if (passTime != 0) System.out.println("虚假唤醒...");
                try {
                    this.wait(surplusWait);//过程中可能会经历虚假唤醒 所以等待timeout-passTime
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passTime = System.currentTimeMillis() - beginTime;
            }
            return result;
        }
    }
}





class GuardedObject{
    private Object result;
    public void complete(Object o){
        synchronized (this){
            result=o;
            this.notifyAll();
        }
    }
    public Object get(long timeout) {
        synchronized (this) {
            long beginTime = System.currentTimeMillis();
            long passTime = 0;
            while (result == null) {
                long surplusWait = timeout - passTime;//剩余等待时间
                if (surplusWait <= 0) {
                    System.out.println("等待超时...");
                    break;
                } else if (passTime != 0) System.out.println("虚假唤醒...");
                try {
                    this.wait(surplusWait);//过程中可能会经历虚假唤醒 所以等待timeout-passTime
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                passTime = System.currentTimeMillis() - beginTime;
            }
            return result;
        }
    }
}
